package com.varian.system.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.varian.mybatis.base.BaseServiceImpl;
import com.varian.mybatis.util.PageUtil;
import com.varian.rabbit.util.RabbitUtil;
import com.varian.system.constant.SystemConstant;
import com.varian.system.convert.SystemConvert;
import com.varian.system.dto.SysTaskPageDTO;
import com.varian.system.entity.SysTask;
import com.varian.system.mapper.SysTaskMapper;
import com.varian.system.service.ISysTaskService;
import com.varian.system.vo.SysTaskVO;
import com.varian.task.model.TaskCreateModel;
import com.varian.task.model.TaskUnprocessModel;
import com.varian.task.model.TaskUpdateModel;
import com.varian.tool.exception.BizException;
import com.varian.tool.model.TaskStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.varian.task.constant.TaskConstant.*;

/**
 * @author ben
 * @since 2024/12/12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysTaskServiceImpl extends BaseServiceImpl<SysTaskMapper, SysTask> implements ISysTaskService {

    private final SystemConvert baseConvert;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processCreateMessage(TaskCreateModel taskCreateModel) {
        SysTask task = baseConvert.toEntity(taskCreateModel);
        task.setTaskStatus(task.getExecuteType().getInitStatus());
        saveOpt(task)
                .ifPresentOrElse(t -> {
                            TaskUnprocessModel model = baseConvert.toUnprocessModel(t);
                            RabbitUtil.send(EXCHANGE_TASK, RK_TASK_EXECUTE, model);
                            RabbitUtil.sendDelay(EXCHANGE_TASK, RK_TASK_TIMEOUT_CHECK, model.getTaskId(), TIMEOUT_CHECK_INTERVAL, TimeUnit.MINUTES);
                        },
                        () -> log.warn("save task fail:{}", task));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processUpdateMessage(TaskUpdateModel taskUpdateModel) {
        // 查询未完成的任务
        SysTask task = baseMapper.selectUncompletedTaskById(taskUpdateModel.getTaskId());
        Optional.ofNullable(task)
                .ifPresentOrElse(t -> {
                    t.setTaskStatus(taskUpdateModel.getTaskStatus())
                            .setExecuteTime(taskUpdateModel.getExecuteTime())
                            .setErrorMessage(taskUpdateModel.getErrorMessage());
                    baseMapper.updateById(t);
                }, () -> log.warn("update task fail:{}", taskUpdateModel));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processTimeoutCheckMessage(Long taskId) {
        // 查询未完成的任务
        SysTask task = baseMapper.selectUncompletedTaskById(taskId);
        Optional.ofNullable(task).ifPresentOrElse(t -> {
            if (t.getCreateTime().plusMinutes(TIMEOUT_CHECK_INTERVAL).isBefore(LocalDateTime.now())) {
                t.setTaskStatus(TaskStatus.FAILURE);
                baseMapper.updateById(t);
            } else {
                RabbitUtil.sendDelay(EXCHANGE_TASK, RK_TASK_TIMEOUT_CHECK, taskId, TIMEOUT_CHECK_INTERVAL, TimeUnit.MINUTES);
            }
        }, () -> log.warn("timeout check task fail:{}", taskId));
    }

    @Override
    public Page<SysTaskVO> page(SysTaskPageDTO dto) {
        Page<SysTask> page = baseMapper.selectPage(dto.toPage(), dto);
        return PageUtil.convert(page, baseConvert::toVO);
    }

    @Override
    public SysTaskVO detail(Long id) {
        SysTask task = baseMapper.selectById(id);
        Assert.notNull(task, () -> BizException.of(SystemConstant.TASK_NOT_EXIST));
        return baseConvert.toVO(task);
    }

}
